﻿using Gargoyle.Roton;
using System;
using System.Collections.Generic;
using System.Text;

namespace Gargoyle.ZZT
{
    static class Interact
    {
        public static void Ammo(Game g, Location location, int index, Vector vector)
        {
            Info info = g.Info;
            Parameters parameters = g.Parameters;
            State state = g.State;

            info.Ammo += (Int16)parameters.AmmoPerPickup;
            g.RemoveItem(location);
            g.UpdateStatus();
            g.PlaySound(2, g.Sounds.Ammo);
            if (state.AlertAmmo)
            {
                g.SetMessageInternal(0xC8, parameters.AmmoMessage, parameters.AmmoPerPickup);
                state.AlertAmmo = false;
            }
            g.UpdateAt(location);
        }

        public static void BoardEdge(Game g, Location location, int index, Vector vector)
        {
            Parameters parameters = g.Parameters;
            State state = g.State;
            Info info = g.Info;
            Board board = g.CurrentBoard;
            Location targetLocation = location;
            Int16 targetBoard;
            Int16 oldBoard;

            if (vector.Y == -1)
            {
                targetLocation.Y = (byte)(g.Size.Height - 2);
                targetBoard = board.ExitNorth;
            }
            else if (vector.Y == 1)
            {
                targetLocation.Y = 1;
                targetBoard = board.ExitSouth;
            }
            else if (vector.X == -1)
            {
                targetLocation.X = (byte)(g.Size.Width - 2);
                targetBoard = board.ExitWest;
            }
            else
            {
                targetLocation.X = 1;
                targetBoard = board.ExitEast;
            }

            if (targetBoard > 0)
            {
                oldBoard = info.Board;
                g.SetBoard(targetBoard);
                if (g.GetElementAt(targetLocation).Id != ElementID.Player)
                {
                    Vector interactVector = state.KeyVector;
                    g.Interact(targetLocation, index, interactVector);
                }
                Element targetElement = g.GetElementAt(targetLocation);
                if (targetElement.Floor || (targetElement.Id == ElementID.Player))
                {
                    if (targetElement.Id != ElementID.Player)
                    {
                        g.MoveThing(0, targetLocation);
                    }
                    g.Fade();
                    vector.X = 0;
                    vector.Y = 0;
                    g.EnterBoard();
                    if (parameters.EnterAlert)
                    {
                        g.BroadcastLabel(0, parameters.EnterLabel);
                    }
                }
                else
                {
                    g.SetBoard(oldBoard);
                }
            }
        }

        public static void Bomb(Game g, Location location, int index, Vector vector)
        {
            Thing thing = g.GetThingAt(location);

            if (thing.P1 > 0)
            {
                g.Push(location, vector);
            }
            else
            {
                thing.P1 = 9;
                g.UpdateAt(thing.Location);
                g.SetMessage(0xC8, g.Parameters.BombMessage);
                g.PlaySound(4, g.Sounds.BombActivate);
            }
        }

        public static void Door(Game g, Location location, int index, Vector vector)
        {
            int color = (g.GetColorAt(location) >> 4) & 0x07;
            bool success;
            Info info = g.Info;
            Parameters parameters = g.Parameters;

            if (color > 0)
            {
                success = (info.Keys[color - 1] != 0);
                if (success)
                    info.Keys[color - 1] = 0;
            }
            else
            {
                success = ((info.Gems & 0xFF00) != 0);
                if (success)
                    info.Gems = (Int16)(info.Gems & 0xFF);

            }
            if (success)
            {
                g.RemoveItem(location);
                g.UpdateStatus();
                g.SetMessageInternal(0xC8, parameters.DoorOpenMessage, color);
                g.PlaySound(3, g.Sounds.DoorOpen);
            }
            else
            {
                g.SetMessageInternal(0xC8, parameters.DoorLockedMessage, color);
                g.PlaySound(3, g.Sounds.DoorLocked);
            }
            g.UpdateAt(location);
        }

        public static void Energizer(Game g, Location location, int index, Vector vector)
        {
            State state = g.State;

            g.PlaySound(9, g.Sounds.Energizer);
            g.RemoveItem(location);
            g.Info.EnergyCycles = 0x4B;
            g.UpdateStatus();

            if (state.AlertEnergy)
            {
                state.AlertEnergy = false;
                g.SetMessage(0xC8, g.Parameters.EnergizerMessage);
            }
            g.BroadcastLabel(0, g.Parameters.EnergizeLabel);
            g.UpdateAt(location);
        }

        public static void Fake(Game g, Location location, int index, Vector vector)
        {
            State state = g.State;

            if (state.AlertFake)
            {
                state.AlertFake = false;
                g.SetMessage(0x96, g.Parameters.FakeWallMessage);
            }
        }

        public static void Forest(Game g, Location location, int index, Vector vector)
        {
            Parameters parameters = g.Parameters;
            State state = g.State;
            
            if (parameters.ForestToFloor)
                g.SetTileAt(location, new Tile(g.Elements.IndexOf(ElementID.Floor), 0x02));
            else
                g.SetElementAt(location, g.Elements[ElementID.Empty]);

            if(g.Type == -2)  // Super ZZT
            {
                byte[] forestSound = new byte[2];
                byte[] sound = g.Sounds.Forest;
                forestSound[0] = sound[state.ForestMusicIndex++];
                forestSound[1] = sound[state.ForestMusicIndex++];
                state.ForestMusicIndex = (state.ForestMusicIndex % sound.Length);
                g.PlaySound(3, forestSound);
            }
            else  // ZZT
            {
                g.PlaySound(3, g.Sounds.Forest);
            }

            if (state.AlertForest)
            {
                state.AlertForest = false;
                g.SetMessage(0xC8, parameters.ForestMessage);
            }
            g.UpdateAt(location);
        }

        public static void Gem(Game g, Location location, int index, Vector vector)
        {
            Info info = g.Info;
            Parameters parameters = g.Parameters;
            State state = g.State;

            info.Gems++;
            info.Health += (Int16)parameters.HealthPerGem;
            info.Score += 10;
            g.RemoveItem(location);
            g.UpdateStatus();
            g.PlaySound(2, g.Sounds.Gem);
            if (state.AlertGem)
            {
                state.AlertGem = false;
                g.SetMessage(0xC8, parameters.GemMessage);
            }
            g.UpdateAt(location);
        }

        public static void Invisible(Game g, Location location, int index, Vector vector)
        {
            g.SetElementAt(location, g.Elements[ElementID.Normal]);
            g.UpdateAt(location);
            g.PlaySound(3, g.Sounds.Invisible);
            g.SetMessage(0x64, g.Parameters.InvisibleMessage);
        }

        public static void Key(Game g, Location location, int index, Vector vector)
        {
            int color = g.GetColorAt(location) & 0x07;
            bool success;
            Info info = g.Info;
            Parameters parameters = g.Parameters;

            if (color > 0)
            {
                success = (info.Keys[color - 1] == 0);
                if (success)
                    info.Keys[color - 1] = 1;
            }
            else
            {
                success = ((info.Gems & 0xFF00) == 0);
                if (success)
                    info.Gems = (Int16)((info.Gems & 0xFF) | 0x100);

            }
            if (success)
            {
                g.RemoveItem(location);
                g.UpdateStatus();
                g.SetMessageInternal(0xC8, parameters.KeyMessage, color);
                g.PlaySound(2, g.Sounds.Key);
            }
            else
            {
                g.SetMessageInternal(0xC8, parameters.KeyAlreadyMessage, color);
                g.PlaySound(2, g.Sounds.KeyAlready);

            }
            g.UpdateAt(location);
        }

        public static void Object(Game g, Location location, int index, Vector vector)
        {
            g.SendLabel(-g.GetThingIndexAt(location), g.Parameters.TouchLabel, false);
        }

        public static void Passage(Game g, Location location, int index, Vector vector)
        {
            byte passageElement = g.Elements.IndexOf(ElementID.Passage);
            Location target = new Location(0, 0);
            Parameters parameters = g.Parameters;
            byte color = g.GetColorAt(location);
            g.SetBoard(g.GetThingAt(location).P3);
            
            Thing player = g.Things[0];
            for (byte x = 0; x < g.Size.Width; x++)
            {
                for (byte y = 0; y < g.Size.Height; y++)
                {
                    Location searchLocation = new Location(x, y);
                    Tile tile = g.GetTileAt(searchLocation);
                    if ((tile.Color == color) && (tile.Element == passageElement))
                    {
                        target.CopyFrom(searchLocation);
                    }
                }
            }

            if (parameters.BuggyPassages)
                g.SetTileAt(g.Things[0].Location, new Tile(g.Elements.IndexOf(ElementID.Empty), 0));
            else
                g.SetTileAt(g.Things[0].Location, g.Things[0].UnderTile);

            if (target.X >= 1)
                g.Things[0].Location.CopyFrom(target);

            g.State.Paused = true;
            g.UpdateStatus();
            g.PlaySound(4, g.Sounds.Passage);
            g.Fade();
            g.EnterBoard();
            vector.CopyFrom(Vector.Idle());

            if (parameters.EnterAlert)
            {
                g.BroadcastLabel(0, parameters.EnterLabel);
            }
        }

        public static void Scroll(Game g, Location location, int index, Vector vector)
        {
            g.PlayMusic(2, "c-c+d-d+e-e+f-f+g-g");
            int scrollIndex = g.GetThingIndexAt(location);
            Thing thing = g.Things[scrollIndex];

            g.ExecuteOOP(scrollIndex, thing.InstructionReference, g.Parameters.DefaultScrollName);
            g.OOPState = null;
            if (g.DisplayBusy)
            {
                g.State.KeyVector = Vector.Idle();
            }
            g.RemoveThing(g.GetThingIndexAt(location));
            g.UpdateAt(location);
        }

        public static void Slime(Game g, Location location, int index, Vector vector)
        {
            byte color = g.GetColorAt(location);
            g.HarmThing(g.GetThingIndexAt(location));
            g.SetTileAt(location, new Tile(g.Elements.IndexOf(ElementID.Breakable), color));
            g.UpdateAt(location);
            g.PlaySound(2, g.Sounds.SlimeDie);
        }

        public static void Stone(Game g, Location location, int index, Vector vector)
        {
            Info info = g.Info;

            if (info.Stones < 0)
                info.Stones = 0;

            info.Stones++;
            g.DestroyAt(location);
            g.UpdateStatus();
            g.SetMessage(0xC8, g.Parameters.StoneMessage);
        }

        public static void Torch(Game g, Location location, int index, Vector vector)
        {
            State state = g.State;
            Info info = g.Info;

            info.Torches++;
            g.RemoveItem(location);
            g.UpdateStatus();
            if (state.AlertTorch)
            {
                g.SetMessage(0xC8, g.Parameters.TorchMessage);
                state.AlertTorch = false;
            }
            g.PlaySound(3, g.Sounds.Torch);
            g.UpdateAt(location);
        }

        public static void Transporter(Game g, Location location, int index, Vector vector)
        {
            g.PushTransporter(location.Subtract(vector), vector);
            vector.CopyFrom(Vector.Idle());
        }

        public static void Water(Game g, Location location, int index, Vector vector)
        {
            g.PlaySound(3, g.Sounds.Water);
            g.SetMessage(0x64, g.Parameters.WaterMessage);
        }

        public static void GenericPushable(Game g, Location location, int index, Vector vector)
        {
            g.Push(location, vector);
            g.PlaySound(2, g.Sounds.Push);
        }

        public static void GenericEnemy(Game g, Location location, int index, Vector vector)
        {
            g.Attack(index, location);
        }

    }
}